﻿using System;
using System.Diagnostics;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;
using System.Management.Automation;
using AmoExtensions;

[assembly: log4net.Config.XmlConfigurator(Watch = true)]
namespace SsasPartitionManager.CmdLet
{
    [Cmdlet(VerbsCommon.Add, "Partitions")]
    public class AddPartitionsCommand : Cmdlet 
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        protected override void ProcessRecord()
        {
            Console.WriteLine("SsasPartitionManager starting");
            try
            {
                string SsasServerName;

                Console.WriteLine("Connecting to partition repository using connection string '{0}'", SsasPartitionManager.CmdLet.Properties.Settings.Default.configDatabaseConnectionString);

                PartitionRepository partitionRepository = new PartitionRepository(
                    SsasPartitionManager.CmdLet.Properties.Settings.Default.configDatabaseConnectionString,
                    SsasPartitionManager.CmdLet.Properties.Settings.Default.sqlListServers,
                    SsasPartitionManager.CmdLet.Properties.Settings.Default.sqlListPartitions
                );

                try
                {
                    SsasServerName = partitionRepository.SsasServerName(SsasPartitionManager.CmdLet.Properties.Settings.Default.SsasServerType);
                }
                catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)
                {
                    string msg = string.Format("Failed to find SsasServerType='{0}' in the spm.SsasServer table. Check your configuration.", SsasPartitionManager.CmdLet.Properties.Settings.Default.SsasServerType);
                    throw new Exception(msg);
                }

                using (AmoServer server = new AmoServer())
                {
                    try
                    {
                        log.InfoFormat("Connecting to '{0}' server: '{1}'", SsasPartitionManager.CmdLet.Properties.Settings.Default.SsasServerType, SsasServerName);

                        if (!server.Connect(SsasServerName))
                        {
                            string msg = string.Format("Failed to connect to the server {0}", SsasServerName);
                            throw new ApplicationException(msg);
                        }

                        // now work out if we need to do any extra steps before we manage the cube partitions, by checking the command-line args
                        // if no command line arguments, then simply manage partitions
                        // if we have a filename and name of the cube, then deploy the cube and create partitions
                        //if (!command.DatabaseName.IsNullOrEmptyOrWhitespace() && !command.AsDatabaseFilePath.IsNullOrEmptyOrWhitespace())
                        //{
                        //    log.InfoFormat("Deploying database '{0}' using AS definition file '{1}'", command.DatabaseName, command.AsDatabaseFilePath);
                        //    if (command.ConnectionStringToDataMart != null)
                        //    {
                        //        log.InfoFormat("Changing the cube's connection string to {0}", command.ConnectionStringToDataMart);    
                        //    }
                            
                        //    // deploy the cube
                        //    server.DeployDatabase(
                        //        command.DatabaseName,
                        //        command.AsDatabaseFilePath,
                        //        command.ConnectionStringToDataMart
                        //    );
                        //}                        

                        PartitionManager pm = new PartitionManager(server);

                        // get a list of partitions we require in each measure group in each cube in each database on the server
                        if (pm.GetListOfPartitions(partitionRepository) > 0)
                        {
                            // validate that the list we got from the server is sensible
                            // 1. check the databases exist
                            // 2. check that the cubes exist
                            // 3. check the measure groups exist
                            // If any partition definition is invalid, it will be logged and the record ignored by the CreatePartitions / DeletePartitions steps
                            if (!pm.IsPartitionListValid())
                                log.Error("Invalid partition information found in SsasPartitions view. See previous error messages for details. These partitions will be ignored.");

                            // create any partitions which are missing
                            pm.CreatePartitions();

                            // delete any partitions which are not listed 
                            pm.DeletePartitions();

                            // update the cube structure - This is rather like T-SQL COMMIT TRANSACTION
                            pm.UpdateCubeMetaData();

                            // process the database or databases depending upon the command-line switch
                            //if (command.ProcessOptions != null)
                            //{
                            //    switch (command.ProcessOptions.ToLower())
                            //    {
                            //        case "processall":
                            //            pm.ProcessAllDatabases();
                            //            break;

                            //        case "processdeployed":
                            //            if (command.DatabaseName != null)
                            //            {
                            //                log.InfoFormat("Processing database '{0}' starting", command.DatabaseName);
                            //                server.ProcessDatabase(command.DatabaseName);
                            //                log.InfoFormat("Processing database '{0}' completed", command.DatabaseName);
                            //            }
                            //            break;

                            //        default:
                            //            // do nothing
                            //            break;
                            //    }
                            //}
                        }
                        else
                        {
                            log.InfoFormat("Failed to retrieve any partition definitions from the SQL database\n  Connection String: '{0}'\nPlease ensure the SsasPartitions view returns a list of partitions.",
                            @"" //SsasPartitionManager.Properties.Settings.Default.configDatabaseConnectionString
                            );
                        }
                    }
                    catch (System.Data.SqlClient.SqlException sqlex)
                    {
                        log.Fatal("Fatal database configuration error encountered: " + sqlex.Message);
                    }
                    catch (ApplicationException aex)
                    {
                        log.Error(aex.Message);
                    }
                    catch(AggregateException aex)
                    {
                        log.Error("Errors encountered during database processing");
                        // we use AggregateExceptions to retrieve all the cube processing errors
                        // so we now need to loop through each inner exception
                        foreach (Exception ex in aex.InnerExceptions)
                        {
                            log.Error(ex.Message);
                        }
                    }
                    catch (Exception ex)
                    {
                        string msg = string.Format("Fatal error encountered: '{0}'", ex.Message);
                        log.Fatal(msg, ex);
                    }
                    log.InfoFormat("Disconnecting from '{0}' server: '{1}'", SsasPartitionManager.CmdLet.Properties.Settings.Default.SsasServerType, SsasServerName);
                }


            }
            catch (System.Data.SqlClient.SqlException sqlex)
            {
                throw new Exception("Fatal database configuration error encountered: " + sqlex.Message);
            }
            catch (Exception ex)
            {
                throw new Exception("Fatal config error occurred: " + ex.Message);                ;
            }
            log.Debug("SsasPartitionManager ending");
        }
    }
}
